﻿using System;
using System.Reflection;
using NLog;
using Schedule;

namespace AllInOnePluginBL.jobs
{
    public class JobsScheduler
    {
        #region Private Members
        private readonly Logger _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);
        private readonly object monitor = new object();
        private readonly ScheduleTimer _Timer = new ScheduleTimer(); 
        #endregion

        #region Delegate
        private delegate void OnTimeElapsedDlg(string jobName, Type jobType, DateTime time); 
        #endregion

        #region Public Properties
        public bool IsStarted { get; private set; } 
        #endregion

        #region Ctor
        public JobsScheduler()
        {
            _Timer.Error += Timer_Error;
        } 
        #endregion

        #region Public Methods
        public void AddJob(string jobName, Type jobType, DateTime startTime, TimeSpan interval)
        {
            _log.Info("Adding Job {0} At {1} With Interval:{2}", jobName, startTime, interval);
            Delegate dlg = new OnTimeElapsedDlg(OnTimeElapsed);
            
            var item = new SimpleInterval(startTime, interval);
            _Timer.AddJob(item, dlg, jobName, jobType);
        }

        public void AddJobDaily(string jobName, Type jobType, TimeSpan startTime)
        {
            _log.Info("Adding Daily Job {0} At {1}", jobName, startTime);
            Delegate dlg = new OnTimeElapsedDlg(OnTimeElapsed);

            var item2 = new ScheduledTime(EventTimeBase.Daily, startTime);
            _Timer.AddJob(item2, dlg, jobName, jobType);
        }

        public void Start()
        {
            return;
            _log.Info("Starting JobsScheduler");
            _Timer.Start();
            IsStarted = true;
            _log.Info("JobsScheduler Started");
        }

        public void Stop()
        {
            _log.Info("Stoping JobsScheduler");
            _Timer.Stop();
            IsStarted = false;
            _log.Info("JobsScheduler Stoped");
        } 
        #endregion

        #region Private Methods
        private void OnTimeElapsed(string jobName, Type jobType, DateTime time)
        {
            lock (monitor)
            {
                _log.Info("Inside OnTimeElapsed");
                var jobInstance = Activator.CreateInstance(jobType) as IJob;
                if (jobInstance == null)
                {
                    _log.Warn("failed to create {0}", jobType.Name);
                    throw new Exception(string.Format("failed to create {0}", jobType.Name));
                }

                _log.Info("Executing {0}...", jobType.Name);
                jobInstance.Execute();
                _log.Info("Job {0} Executed", jobType.Name);
            }
        }

        private void Timer_Error(object sender, ExceptionEventArgs Args)
        {
            _log.Error("JobsScheduler Got Error EventTime: {0}", Args.EventTime);
            _log.ErrorException("JobsScheduler Got Error Message", Args.Error.GetBaseException());
            _log.Error("JobsScheduler Got Error StackTrace: {0}", Args.Error.StackTrace);
        } 
        #endregion
    }
}
